package gamedsl.game;

import java.util.ArrayList;

import gamedsl.event.Event;
import gamedsl.event.EventTracker;
import gamedsl.event.IEventHandler;

import org.lwjgl.opengl.GL11;
import org.newdawn.penguin.*;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;


public class PlayingGameState extends BasicGameState implements 
IEventHandler{

	private static final int ID = 1;
	private Environment env;
	private ActorPhysics player;
	private float xoffset;
	private float yoffset;
	private Image background;
	private ArrayList<Event> triggerEvents;
	private GameContainer gc;
	
	private int totalDelta;
	private int prevTotalDelta = 0;
		private int controlInterval = 50;
		private int timeoutInterval = 5000;
		private int score = 0;
	
	
	@Override
	public void init(GameContainer arg0, StateBasedGame arg1)
			throws SlickException {
			
		background = new Image("res/cave.png");
		
		//subscribe to tracker
			EventTracker.getInstance().subscribe("MushroomRewardHitEvent",this);
		//EventTracker.getInstance().subscribe("MushroomRewardHitEvent", this);
		gc = arg0;
		
		restart();
		
	}

	@Override
	public void render(GameContainer container, StateBasedGame game, Graphics g)
			throws SlickException {
		float width = container.getWidth();
		float height = container.getHeight();
		float backPar = 3f;
		float bx = ((-xoffset * backPar) % width) / -width;
		float by = ((-yoffset * backPar) % height) / -height;
		background.bind();
		g.setColor(Color.white);
		GL11.glBegin(GL11.GL_QUADS);
			GL11.glTexCoord2f(bx,by);
			GL11.glVertex2f(0,0);
			GL11.glTexCoord2f(bx+3,by);
			GL11.glVertex2f(width,0);
			GL11.glTexCoord2f(bx+3,by+3);
			GL11.glVertex2f(width,height);
			GL11.glTexCoord2f(bx,by+3);
			GL11.glVertex2f(0,height);
		GL11.glEnd();
		
		g.translate(-(int) xoffset, -(int) yoffset);
		
		env.render(g);
		//draw the score
		g.drawString("Score: " + score, xoffset+10, yoffset+30);
		
	}

	@Override
	public void update(GameContainer container, StateBasedGame game, int delta)
			throws SlickException {
	Input input = container.getInput();
		
		// restart and bounds toggling
		if (input.isKeyPressed(Input.KEY_R)) {
			restart();
			return;
		}

		// the forces applied for different actions. The move force is applied over and
		// over so is reasonably small. The jump force is a one shot deal and so is reasonably
		// big
//		float moveForce = 100;
//		float jumpForce = 20000;

		float moveForce = 500.0f;
		float jumpForce = 15000.0f;
		
		totalDelta += delta;
		
		// setup the player's moving flag, this control the animation
		player.setMoving(false);
		if (input.isKeyDown(Input.KEY_LEFT)) {
			player.setMoving(true);
		}
		if (input.isKeyDown(Input.KEY_RIGHT)) {
			player.setMoving(true);
		}
		
		// only check controls at set interval. If we don't do this different
		// frame rates will effect how the controls are interpreted
		if (totalDelta > controlInterval) {
			controlInterval -= totalDelta;
			
			if (input.isKeyDown(Input.KEY_LEFT)) {
				player.applyForce(-moveForce, 0);
			}
			if (input.isKeyDown(Input.KEY_RIGHT)) {
				player.applyForce(moveForce, 0);
			}
			if (player.onGround()) {
				if ((input.isKeyPressed(Input.KEY_LCONTROL)) || 
				   (input.isKeyPressed(Input.KEY_RCONTROL))) {
					if (player.facingRight()) {
						player.applyForce(0, -jumpForce);
					} else {
						player.applyForce(0, -jumpForce);
					}
				}
			}
			if (!input.isKeyDown(Input.KEY_LCONTROL)) {
				if (player.jumping()) {
					player.setVelocity(player.getVelX(), player.getVelY() * 0.95f);
				}
			}
		}
		
		//has time out occurred
		if(totalDelta - prevTotalDelta > timeoutInterval){
			//generate a new mushroom
			((AbstractEnvironment)env).addEntity(new MushroomReward(700, 100, 21,21,1,"m", "MushroomReward",5));
			prevTotalDelta = totalDelta;
			
		}
		
		// update the environemnt and hence the physics world
		env.update(delta);
		
		// calculate screen position clamping to the bounds of the level
		xoffset = player.getX() - 400;
		yoffset = player.getY() - 300;
		
		Rectangle bounds = env.getBounds();
		if (xoffset < bounds.getX()) {
			xoffset = bounds.getX();
		}
		if (yoffset < bounds.getY()) {
			yoffset = bounds.getY();
		}
		
		if (xoffset > (bounds.getX() + bounds.getWidth()) - 800) {
			xoffset = (bounds.getX() + bounds.getWidth()) - 800;
		}
		if (yoffset > (bounds.getY() + bounds.getHeight()) - 600) {
			yoffset = (bounds.getY() + bounds.getHeight()) - 600;
			int height = gc.getScreenHeight();
			int width = gc.getScreenWidth();
		}
	/*	
		if (xoffset > (bounds.getX() + bounds.getWidth()) - gc.getScreenWidth()) {
			xoffset = (bounds.getX() + bounds.getWidth()) - gc.getScreenWidth();
		}
		if (yoffset > (bounds.getY() + bounds.getHeight()) - gc.getScreenHeight()) {
			yoffset = (bounds.getY() + bounds.getHeight()) - gc.getScreenHeight();
		}
		*/
	}
	

	@Override
	public int getID() {
		return this.ID;
	}
	
	private void drawString(Graphics g, String str, int y) {
		int x = (gc.getScreenWidth() - g.getFont().getWidth(str)) / 2;
		g.setColor(Color.black);
		g.drawString(str, x+1,y+1);
		g.setColor(Color.white);
		g.drawString(str, x,y);
		
	}
	
	
	public void restart() throws SlickException{
		buildWorld();
		addGameEntities();
	}
	
	/*
	 * Create the Environment. Load the map
	 */
	private void buildWorld() throws SlickException{
		TileSet set = new TileSet("res/tiles.xml");
		MapLoader loader = new MapLoader(set);
		TileEnvironment env = loader.load("res/testmap.txt");
		env.setImageSize(32,32);
		env.init();
		this.env = env;
	}
	
	/*
	 * Populate the Environment with game entities 
	 */
	private void addGameEntities() throws SlickException{
		//player = new Alien(100,150,1f,24, "player", "Player",0);
		
				player = new Alien(100.0f, 50.0f, 10.0f, 20.0f, "Alien","Player",1);

		AbstractEnvironment aEnv = (AbstractEnvironment) env;
		aEnv.addEntity(player);
		
		aEnv.addEntity(new Crate(600.0f,200.0f,20.0f,20.0f,1.0f, "Crate", "Crate",111));

						aEnv.addEntity(new MushroomReward(600.0f,111.0f,15.0f,15.0f,1.0f, "MushroomReward1", "MushroomReward",0));
						aEnv.addEntity(new Crate(500.0f,100.0f,33.0f,33.0f,10.0f, "Crate1", "Crate",1));
		
	}
	
	public void handleEvent(Event event){
		System.out.println("PlayingGameState Event: " + event.getMessage());
		AbstractEnvironment aEnv = (AbstractEnvironment) env;
		
					if(event.getMessage() == "MushroomRewardHitEvent"){
						Entity entity = (Entity)event.getObjectSrc();
						//increase score
						score += ((AbstractEntity)entity).getValue();
						//remove object from game world
						aEnv.removeEntity(entity);
					}

	}

	@Override
	public int getHandlerId() {
		return this.ID;
	}
	
}
